/**
 * 上传文件的弹窗
 */

import React from 'react';
import PropTypes from 'prop-types';
import { Dialog, Field, Message, Form, Upload } from '@teamix/ui';
import { YunxiaoIcon } from '@alife/devops-ui';
import { navigate } from 'utils/router';
import FileBasicForm from 'components/fileBasicForm';
import UILessAssociateTask from 'components/UILessAssociateTask';
import utils from 'utils';
import '../index.scss';
import { getAllFiles } from 'api';
import docs from 'utils/docs';
import intl from '../../../../../../../../../locale';

const { pathResource, resourceSubject } = window.FORCE;

/**
 * File转base64的函数
 */
function getBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = (error) => reject(error);
  });
}

export default class UploadFile extends React.Component {
  static propTypes = {
    trigger: PropTypes.element,
    closeModal: PropTypes.func,
  };

  static defaultProps = {
    trigger: null,
    closeModal: () => {},
  };

  constructor(props) {
    super(props);
    this.field = new Field(this);
    this.state = {
      isDialogVisible: false,
      submitting: false,
      existFileList: [],
      task_ids: '',
    };
  }

  static getDerivedStateFromProps(props) {
    if (props.trigger) {
      return {};
    }
    return {
      isDialogVisible: props.isDialogVisible,
    };
  }

  componentDidMount() {
    if (!this.props.trigger) {
      this.fetchFiles();
    }
  }

  onDialogOpen = () => {
    this.setState({ isDialogVisible: true });
    this.fetchFiles();
  };

  fetchFiles = () => {
    if (window.FORCE.pathResource.isEmpty !== 'true') {
      getAllFiles()
        .then((result) => {
          result.shift();
          this.setState({
            existFileList: result,
          });
        })
        .catch((err) => {
          console.log(err);
        });
    }
  };

  saveUploaderRef = (ref) => {
    this.uploaderRef = ref.getInstance();
  };

  sizeCaculator(size) {
    let fileSize = parseFloat(size, 10);
    // fileSize为浮点数 用 < 0.000001 替代 === 0
    if (isNaN(fileSize) || fileSize < 0.0000001) {
      return '0B';
    }
    const SIZE_SUFFIX = ['B', 'K', 'M', 'G', 'T', 'P'];
    let suffixIndex = 0;

    // 在Mac上实验发现 取1024造成显示的大小和实际大小不一致
    // 因为单位制不同 见 https://superuser.com/questions/938234/size-of-files-in-windows-os-its-kb-or-kb
    const BIT_NUMBER_SYSTEM = 1024;
    while (fileSize >= BIT_NUMBER_SYSTEM && suffixIndex < SIZE_SUFFIX.length) {
      suffixIndex += 1;
      fileSize /= BIT_NUMBER_SYSTEM;
    }

    const suffix = SIZE_SUFFIX[suffixIndex];
    fileSize = fileSize.toFixed(2);

    return `${fileSize}${suffix}`;
  }

  onDialogOk = () => {
    if (this.state.submitting) return;
    this.setState({ submitting: true });
    const { resourcePath, isMaster } = this.props;
    this.field.validate((errors) => {
      if (!errors) {
        const formData = this.field.getValues();
        const filePath = this.field.getValue('file_path');
        const commit_message = formData.commit_message_content
          ? `${formData.commit_message_title}\n${formData.commit_message_content}`
          : formData.commit_message_title;
        const file = filePath[0].originFileObj;

        const fileSizeWithUnit = this.sizeCaculator(file.size);
        const fileSizeUnit = fileSizeWithUnit.charAt(fileSizeWithUnit.length - 1);
        const fileSize = parseInt(fileSizeWithUnit.substr(0, fileSizeWithUnit.length - 1));

        if (fileSizeUnit === 'M') {
          if (fileSize > 50) {
            Message.error({
              title: (
                <div>
                  {intl.get({
                    id: 'code-assets.content.dialog.uploadFile.UploadFailedASingleFile',
                    defaultMessage: '上传失败，单文件需小于50M，大文件建议通过命令行使用',
                  })}
                  <a href={docs('largeFileStorageService')} target="_blank" rel="noreferrer">
                    {intl.get({
                      id: 'code-assets.content.dialog.uploadFile.LargeFileStorageServiceLfs',
                      defaultMessage: '大文件存储服务（LFS）',
                    })}
                  </a>
                  {intl.get({
                    id: 'code-assets.content.dialog.uploadFile.Management',
                    defaultMessage: '管理',
                  })}
                </div>
              ),
              duration: 2000,
            });

            this.setState({ submitting: false });
            return;
          }
        } else if (fileSizeUnit === 'K' || fileSizeUnit === 'B') {
          console.log('support');
        } else {
          Message.error({
            title: (
              <div>
                {intl.get({
                  id: 'code-assets.content.dialog.uploadFile.UploadFailedASingleFile',
                  defaultMessage: '上传失败，单文件需小于50M，大文件建议通过命令行使用',
                })}
                <a href={docs('largeFileStorageService')} target="_blank" rel="noreferrer">
                  {intl.get({
                    id: 'code-assets.content.dialog.uploadFile.LargeFileStorageServiceLfs',
                    defaultMessage: '大文件存储服务（LFS）',
                  })}
                </a>
                {intl.get({
                  id: 'code-assets.content.dialog.uploadFile.Management',
                  defaultMessage: '管理',
                })}
              </div>
            ),
            duration: 2000,
          });
          this.setState({ submitting: false });
          return;
        }

        if (isMaster !== 1) {
          formData.file_path = `${resourcePath}/${file.name}`;
        } else {
          formData.file_path = file.name;
        }

        getBase64(file)
          .then((base64File) => {
            const revision = resourceSubject.revision || 'master';
            formData.content = file.size === 0 ? '' : base64File.replace(/^.*;base64,/, '');
            if (this.state.task_ids) {
              formData.task_ids = this.state.task_ids;
            }
            this.props.createFile(
              formData,
              commit_message,
              () => {
                Message.success({
                  title: intl.get({
                    id: 'code-assets.content.dialog.uploadFile.FileUploaded',
                    defaultMessage: '上传文件成功',
                  }),
                });

                this.setState({ isDialogVisible: false });
                if (isMaster !== 1) {
                  navigate(
                    `/${pathResource.fullPath}/blob/${utils.revisionEncodeURI(
                      revision,
                    )}/${resourcePath}${resourcePath ? '/' : ''}${file.name}`,
                    { state: { forceUpdate: true } },
                  );
                } else {
                  navigate(
                    `/${pathResource.fullPath}/blob/${utils.revisionEncodeURI(revision)}/${
                      file.name
                    }`,
                    { state: { forceUpdate: true } },
                  );
                }
              },
              () => {
                this.setState({ submitting: false });
              },
            );
          })
          .catch(() => {
            Message.error({
              title: intl.get({
                id: 'code-assets.content.dialog.uploadFile.YouCannotUploadFoldersPlease',
                defaultMessage: '不支持上传文件夹，请重新选择文件',
              }),
              duration: 2000,
            });

            this.setState({ submitting: false });
          });
      } else {
        this.setState({ submitting: false });
      }
    });
  };

  onDialogCancel = () => {
    this.setState({ isDialogVisible: false });
    this.props.closeModal();
  };

  nameValidator = (rule, value, callback) => {
    const { existFileList } = this.state;
    const { resourcePath, isMaster } = this.props;

    if (!value) {
      callback();
      return;
    }

    const fileName = value[0].name;
    const result = existFileList.some((i) => {
      return isMaster ? fileName === i.path : `${resourcePath}/${fileName}` === i.path;
    });
    result &&
      callback(
        intl.get({
          id: 'code-assets.content.dialog.uploadFile.TheFileAlreadyExists',
          defaultMessage: '文件已存在',
        }),
      );

    callback();
  };

  render() {
    const { init } = this.field;
    const filePath = this.field.getValue('file_path') || '';
    const fileName =
      filePath &&
      filePath.map((item) => {
        return item.name;
      });
    const { isMaster, resourcePath } = this.props;
    // 空库增加提示
    const emptyHelp =
      window.FORCE.pathResource.isEmpty === 'true' ? (
        <div className="upload-file-path-help">
          {intl.get({
            id: 'code-assets.content.dialog.uploadFile.TipsDoYouWantTo',
            defaultMessage: 'Tips：想批量关联文件？使用命令行或三方库导入功能',
          })}
          <a href={docs('associatedFolder')} target="_blank" rel="noreferrer">
            {intl.get({
              id: 'code-assets.content.dialog.uploadFile.AssociateAnExistingFolderOr',
              defaultMessage: '关联已有文件夹或仓库',
            })}
          </a>
          {intl.get({ id: 'code-assets.content.dialog.uploadFile.Ok', defaultMessage: '吧~' })}
        </div>
      ) : null;

    return (
      <React.Fragment>
        {this.state.isDialogVisible ? (
          <Dialog
            visible
            onOk={this.onDialogOk}
            onCancel={this.onDialogCancel}
            onClose={this.onDialogCancel}
            title={intl.get({
              id: 'code-assets.content.dialog.uploadFile.UploadObjects',
              defaultMessage: '上传文件',
            })}
            style={{
              width: '600px',
            }}
            okProps={{
              children: intl.get({
                id: 'code-assets.content.dialog.uploadFile.Upload',
                defaultMessage: '上传',
              }),
              loading: this.state.submitting,
            }}
            cancelProps={{
              children: intl.get({
                id: 'code-assets.content.dialog.uploadFile.Cancel',
                defaultMessage: '取消',
              }),
            }}
            footerActions={['cancel', 'ok']}
            onChange={(info) => {
              console.log(info);
            }}
          >
            {!isMaster && resourcePath && (
              <div className="upload-path">
                <span style={{ marginRight: 8 }}>
                  {intl.get({
                    id: 'code-assets.content.dialog.uploadFile.UploadDirectory',
                    defaultMessage: '上传目录',
                  })}
                </span>{' '}
                {resourcePath}
              </div>
            )}

            <Form direction="ver" field={this.field} style={{ marginBottom: 8 }}>
              <Form.Item
                label={intl.get({
                  id: 'code-assets.content.dialog.uploadFile.SelectAFile',
                  defaultMessage: '选择文件',
                })}
                required
                help={
                  this.field.getState('file_path') === 'error'
                    ? this.field.getError('file_path')
                    : emptyHelp
                }
              >
                <Upload.Dragger
                  limit={1}
                  autoUpload={false}
                  listType="text"
                  {...init('file_path', {
                    rules: [
                      {
                        required: true,
                        message: intl.get({
                          id: 'code-assets.src.utils.locale.ThisParameterIsRequired',
                          defaultMessage: '该项为必填项',
                        }),
                      },
                      { validator: this.nameValidator },
                    ],
                  })}
                >
                  <div className="upload-file">
                    <span>
                      <YunxiaoIcon type="add-line" />
                      {intl.get({
                        id: 'code-assets.content.dialog.uploadFile.AddOrDragAndDrop',
                        defaultMessage: '添加文件 或 将文件拖放至此区域',
                      })}
                    </span>
                  </div>
                </Upload.Dragger>
              </Form.Item>
            </Form>
            <FileBasicForm
              field={this.field}
              label={intl.get({
                id: 'code-assets.content.dialog.uploadFile.SubmissionInformation',
                defaultMessage: '提交信息',
              })}
              defaultCommitMsg={intl.get(
                {
                  id: 'code-assets.content.dialog.uploadFile.UploadFilename',
                  defaultMessage: '上传 {fileName}',
                },
                { fileName },
              )}
            />

            <UILessAssociateTask
              useBy="submit"
              onChange={(items) => {
                if (!items.map) {
                  return;
                }
                const task_ids = items.map((item) => {
                  return item._id;
                });
                this.setState({
                  task_ids: task_ids.join(','),
                });
              }}
            />
          </Dialog>
        ) : null}
        {!!this.props.trigger &&
          React.cloneElement(this.props.trigger, {
            onClick: (e) => {
              this.props.trigger.props.onClick && this.props.trigger.props.onClick(e);
              this.onDialogOpen();
            },
          })}
      </React.Fragment>
    );
  }
}
